ParentPersistersStep.java
package org.codefilarete.stalactite.engine.configurer.builder;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.function.Function;
import org.codefilarete.stalactite.dsl.embeddable.EmbeddableMappingConfiguration;
import org.codefilarete.stalactite.engine.cascade.AfterDeleteByIdSupport;
import org.codefilarete.stalactite.engine.cascade.AfterDeleteSupport;
import org.codefilarete.stalactite.engine.cascade.AfterUpdateSupport;
import org.codefilarete.stalactite.engine.cascade.BeforeInsertSupport;
import org.codefilarete.stalactite.engine.configurer.AbstractIdentification;
import org.codefilarete.stalactite.engine.configurer.builder.InheritanceMappingStep.Mapping;
import org.codefilarete.stalactite.engine.configurer.builder.InheritanceMappingStep.MappingPerTable;
import org.codefilarete.stalactite.engine.listener.PersisterListenerCollection;
import org.codefilarete.stalactite.engine.listener.UpdateByIdListener;
import org.codefilarete.stalactite.engine.runtime.SimpleRelationalEntityPersister;
import org.codefilarete.stalactite.engine.runtime.load.EntityJoinTree;
import org.codefilarete.stalactite.engine.runtime.load.EntityMerger.EntityMergerAdapter;
import org.codefilarete.stalactite.mapping.DefaultEntityMapping;
import org.codefilarete.stalactite.sql.ConnectionConfiguration;
import org.codefilarete.stalactite.sql.Dialect;
import org.codefilarete.stalactite.sql.ddl.structure.PrimaryKey;
import org.codefilarete.stalactite.sql.ddl.structure.Table;
import org.codefilarete.tool.collection.Iterables;
import org.codefilarete.tool.collection.KeepOrderSet;
import org.codefilarete.tool.collection.ReadOnlyIterator;
import org.codefilarete.tool.function.Hanger.Holder;
import static org.codefilarete.stalactite.engine.configurer.builder.MainPersisterStep.createEntityMapping;
import static org.codefilarete.tool.collection.Iterables.first;
/**
* Build parent persisters and add cascade between child and parent table.
*
* @param <C>
* @param <I>
* @author Guillaume Mary
*/
public class ParentPersistersStep<C, I> {
void buildParentPersisters(SimpleRelationalEntityPersister<C, I, ?> mainPersister,
AbstractIdentification<C, I> identification,
MappingPerTable<C> inheritanceMappingPerTable,
Dialect dialect,
ConnectionConfiguration connectionConfiguration) {
Mapping<C, ?> mainMapping = first(inheritanceMappingPerTable.getMappings());
// parent persister must be kept in ascending order for below treatment
ReadOnlyIterator<Mapping<C, ?>> inheritedMappingIterator = Iterables.reverseIterator(inheritanceMappingPerTable.getMappings().getDelegate());
Iterator<Mapping<C, ?>> mappings = Iterables.filter(inheritedMappingIterator,
m -> !mainMapping.equals(m) && !m.isMappedSuperClass());
KeepOrderSet<SimpleRelationalEntityPersister<C, I, ?>> parentPersisters = this.buildParentPersisters(() -> mappings,
identification, mainPersister, dialect, connectionConfiguration
);
addCascadesBetweenChildAndParentTable(mainPersister, parentPersisters);
}
private <T extends Table<T>, TT extends Table<TT>> KeepOrderSet<SimpleRelationalEntityPersister<C, I, ?>> buildParentPersisters(Iterable<Mapping<C, ?>> mappings,
AbstractIdentification<C, I> identification,
SimpleRelationalEntityPersister<C, I, T> mainPersister,
Dialect dialect,
ConnectionConfiguration connectionConfiguration) {
KeepOrderSet<SimpleRelationalEntityPersister<C, I, ?>> result = new KeepOrderSet<>();
PrimaryKey<T, I> superclassPK = mainPersister.getMainTable().getPrimaryKey();
Holder<Table> currentTable = new Holder<>(mainPersister.getMainTable());
mappings.forEach(mapping -> {
// we skip already configured inherited persister to avoid getting an error while adding results of buildParentPersisters(..) method
// to the persister registry due to prohibition to add twice persister dealing with same entity type
if (mapping.getMappingConfiguration() instanceof EmbeddableMappingConfiguration) {
Class<?> entityType = ((EmbeddableMappingConfiguration<?>) mapping.getMappingConfiguration()).getBeanType();
if (PersisterBuilderContext.CURRENT.get().getPersisterRegistry().getPersister(entityType) != null) {
return;
}
}
Mapping<C, TT> castedMapping = (Mapping<C, TT>) mapping;
PrimaryKey<TT, I> subclassPK = castedMapping.getTargetTable().getPrimaryKey();
boolean isIdentifyingConfiguration = identification.getIdentificationDefiner().getPropertiesMapping() == mapping.giveEmbeddableConfiguration();
DefaultEntityMapping<C, I, TT> currentMappingStrategy = createEntityMapping(
isIdentifyingConfiguration,
castedMapping.getTargetTable(),
castedMapping.getMapping(),
castedMapping.getReadonlyMapping(),
castedMapping.getReadConverters(),
castedMapping.getWriteConverters(),
castedMapping.getPropertiesSetByConstructor(),
identification,
mapping.giveEmbeddableConfiguration().getBeanType(),
null);
SimpleRelationalEntityPersister<C, I, TT> currentPersister = new SimpleRelationalEntityPersister<>(currentMappingStrategy, dialect, connectionConfiguration);
result.add(currentPersister);
// a join is necessary to select entity, only if target table changes
if (!currentPersister.getMainTable().equals(currentTable.get())) {
mainPersister.getEntityJoinTree().addMergeJoin(EntityJoinTree.ROOT_JOIN_NAME, new EntityMergerAdapter<>(currentMappingStrategy), superclassPK, subclassPK);
currentTable.set(currentPersister.getMainTable());
}
});
return result;
}
/**
*
* @param mainPersister main persister
* @param superPersisters persisters in ascending order
*/
private <T extends Table<T>> void addCascadesBetweenChildAndParentTable(SimpleRelationalEntityPersister<C, I, T> mainPersister,
KeepOrderSet<SimpleRelationalEntityPersister<C, I, ?>> superPersisters) {
// we add cascade only on persister with different table : we keep the "lowest" one because it gets all inherited properties,
// upper ones are superfluous
KeepOrderSet<SimpleRelationalEntityPersister<C, I, ?>> superPersistersWithChangingTable = new KeepOrderSet<>();
Holder<Table> lastTable = new Holder<>(mainPersister.getMainTable());
superPersisters.forEach(p -> {
if (!p.getMainTable().equals(lastTable.get())) {
superPersistersWithChangingTable.add(p);
}
lastTable.set(p.getMainTable());
});
PersisterListenerCollection<C, I> persisterListener = mainPersister.getPersisterListener();
superPersistersWithChangingTable.forEach(superPersister -> {
// Before insert of child we must insert parent
persisterListener.addInsertListener(new BeforeInsertSupport<>(superPersister::insert, Function.identity()));
// On child update, parent must be updated too, no constraint on order for this, after is arbitrarily chosen
persisterListener.addUpdateListener(new AfterUpdateSupport<>(superPersister::update, Function.identity()));
// idem for updateById
persisterListener.addUpdateByIdListener(new UpdateByIdListener<C>() {
@Override
public void afterUpdateById(Iterable<? extends C> entities) {
superPersister.updateById(entities);
}
});
});
List<SimpleRelationalEntityPersister<C, I, ?>> copy = Iterables.copy(superPersistersWithChangingTable);
Collections.reverse(copy);
copy.forEach(superPersister -> {
// On child deletion, parent must be deleted after
persisterListener.addDeleteListener(new AfterDeleteSupport<>(superPersister::delete, Function.identity()));
// idem for deleteById
persisterListener.addDeleteByIdListener(new AfterDeleteByIdSupport<>(superPersister::deleteById, Function.identity()));
});
}
}